package com.jzo2o.market.handler;

import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.JsonUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.market.constants.RedisConstants;
import com.jzo2o.market.enums.ActivityStatusEnum;
import com.jzo2o.market.enums.CouponStatusEnum;
import com.jzo2o.market.model.domain.Activity;
import com.jzo2o.market.model.domain.Coupon;
import com.jzo2o.market.model.dto.response.ActivityInfoResDTO;
import com.jzo2o.market.service.IActivityService;
import com.jzo2o.market.service.ICouponService;
import com.jzo2o.market.task.SyncMessageTask;
import com.jzo2o.redis.sync.SyncManager;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.jzo2o.market.enums.ActivityStatusEnum.DISTRIBUTING;
import static com.jzo2o.market.enums.ActivityStatusEnum.NO_DISTRIBUTE;

@Component
@Slf4j
public class XxlJobHandler {

    @Resource
    private SyncManager syncManager;

    @Resource
    private IActivityService activityService;

    @Resource
    private ICouponService couponService;

    /**
     * 活动状态修改，
     * 1.活动进行中状态修改
     * 2.活动已失效状态修改
     * 1分钟一次
     */
    @XxlJob("updateActivityStatus")
    public void updateActivitySatus() {
        //查询活动优惠券
        List<Activity> activityList = activityService.lambdaQuery().eq(Activity::getStatus, NO_DISTRIBUTE.getStatus())
                .or().eq(Activity::getStatus, DISTRIBUTING.getStatus()).list();

        for (Activity activity : activityList) {
            //判断是否到达开启活动时间
            if (activity.getStatus().equals(NO_DISTRIBUTE.getStatus()) && LocalDateTime.now().isAfter(activity.getDistributeStartTime())) {
                //修改状态为进行中
                activityService.lambdaUpdate().eq(Activity::getId, activity.getId())
                        .set(Activity::getStatus, DISTRIBUTING.getStatus())
                        .update();
            } else if (activity.getStatus().equals(DISTRIBUTING.getStatus()) && LocalDateTime.now().isAfter(activity.getDistributeEndTime())) {
                //修改为已作废
                activityService.lambdaUpdate().eq(Activity::getId, activity.getId())
                        .set(Activity::getStatus, ActivityStatusEnum.VOIDED.getStatus())
                        .update();
            }
        }
    }

    /**
     * 已领取优惠券自动过期任务
     */
    @XxlJob("processExpireCoupon")
    public void processExpireCoupon() {
        //查询coupon表
        List<Coupon> list = couponService.list();
        for (Coupon coupon : list) {
            if (LocalDateTime.now().isAfter(coupon.getValidityTime())) {
                boolean update = couponService.lambdaUpdate()
                        .set(Coupon::getStatus, CouponStatusEnum.VOIDED.getStatus())
                        .eq(Coupon::getStatus, CouponStatusEnum.NO_USE.getStatus())
                        .update();
                if (!update) {
                    throw new DBException("修改coupon数据库状态失败");
                }
            }
        }
    }


    /**
     * 符合条件定时预热优惠券活动列表
     */
    @Autowired
    private RedisTemplate redisTemplate;

    @XxlJob("activityPreheat")
    public void activityPreheat() {
        //1.查询活动状态为未开始与进行中的&&在未来一个月内要开始的
        List<Activity> activityList = activityService.lambdaQuery()
                .in(Activity::getStatus, NO_DISTRIBUTE.getStatus(), DISTRIBUTING.getStatus())
                .lt(Activity::getDistributeStartTime, LocalDateTime.now().plusDays(30))
                .orderByDesc(Activity::getDistributeStartTime)
                .list();
        if (CollUtils.isEmpty(activityList)) {
            activityList = new ArrayList<>();
        }
        //2.转为前端需要的对象
        List<ActivityInfoResDTO> activityInfoResDTOList = BeanUtils.copyToList(activityList, ActivityInfoResDTO.class);
        //3.将对象转为json字符串
        String jsonStr = JsonUtils.toJsonStr(activityInfoResDTOList);
        //4.存放到redis中
        redisTemplate.opsForValue().set(RedisConstants.RedisKey.ACTIVITY_CACHE_LIST, jsonStr);


        //二、第二部分数据预热：活动库存
        //1. 待开始的活动，所有活动的库存信息全部预热到缓存
        activityInfoResDTOList.stream()
                .filter(x -> ObjectUtils.equals(x.getStatus(), NO_DISTRIBUTE.getStatus()))
                .forEach(x -> {
                    String redisKeyStock = String.format(RedisConstants.RedisKey.COUPON_RESOURCE_STOCK, x.getId() % 10);
                    redisTemplate.opsForHash().put(redisKeyStock, x.getId(), x.getStockNum());
                });

        //2. 进行中的活动，缓存中没数据时才预热到缓存
        activityInfoResDTOList.stream()
                .filter(x -> ObjectUtils.equals(x.getStatus(), DISTRIBUTING.getStatus()))
                .forEach(x -> {
                    String redisKeyStock = String.format(RedisConstants.RedisKey.COUPON_RESOURCE_STOCK, x.getId() % 10);
                    redisTemplate.opsForHash().putIfAbsent(redisKeyStock, x.getId(), x.getStockNum());
                });
    }

    @Autowired
    private SyncMessageTask syncMessageTask;

    /**
     * 抢券结果同步任务
     */
    @XxlJob("seizeCouponSyncJob")
    public void seizeCouponSyncJob() {
        log.info("抢券结果同步定时任务...");
        try {
            for (long index = 0; index < 10; index++) {
                //提交10个异步任务，让10个不同的线程去处理各自的同步队列数据
                syncMessageTask.batchHandeSyncMessage(index);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
